#pragma once

/*
 * UAE - The Un*x Amiga Emulator
 *
 * Events
 * These are best for low-frequency events. Having too many of them,
 * or using them for events that occur too frequently, can cause massive
 * slowdown.
 *
 * Copyright 1995-1998 Bernd Schmidt
 */

#include "rpt.h"

extern volatile frame_time_t vsynctime, vsyncmintime;
extern void reset_frame_rate_hack();
extern int rpt_available;
extern frame_time_t syncbase;
extern uint vsync_cycles;
extern uint start_cycles;

extern void compute_vsynctime();
extern void init_eventtab();
extern void do_cycles_ce(uint cycles);
extern int is_cycle_ce();

extern uint currcycle, nextevent, is_lastline;
typedef void (*evfunc)();
typedef void (*evfunc2)(uint);

typedef uint evt;

struct ev
{
    bool active;
    evt evtime, oldcycles;
    evfunc handler;
};

struct ev2
{
    bool active;
    evt evtime;
    uint data;
    evfunc2 handler;
};

enum
{
    ev_cia, ev_audio, ev_misc, ev_hsync,
    ev_max
};

enum
{
    ev2_blitter, ev2_disk, ev2_misc,
    ev2_max= 12
};

extern struct ev eventtab[ev_max];
extern struct ev2 eventtab2[ev2_max];

#if 0
    #ifdef JIT
        #include "events_jit.h"
    #else
        #include "events_normal.h"
    #endif
#else
    #include "events_jit.h"
#endif

static __forceinline int current_hpos()
{
    return (get_cycles() - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
}

static __forceinline bool cycles_in_range(uint endcycles)
{
    int c = get_cycles();
    return (int)endcycles - c > 0;
}

extern void MISC_handler();

static __forceinline void event2_newevent_xx(int no, evt t, uint data, evfunc2 func)
{
    evt et;
    static int next = ev2_misc;

    et = t + get_cycles();
    if (no < 0)
    {
        no = next;
        for (;;)
        {
            if (!eventtab2[no].active)
                break;
            if (eventtab2[no].evtime == et && eventtab2[no].handler == func)
            {
                eventtab2[no].handler(eventtab2[no].data);
                break;
            }
            no++;
            if (no == ev2_max)
                no = ev2_misc;
            if (no == next)
            {
                Logger::Write(L"out of event2's!\n");
                return;
            }
        }
        next = no;
    }
    eventtab2[no].active = true;
    eventtab2[no].evtime = et;
    eventtab2[no].handler = func;
    eventtab2[no].data = data;
    MISC_handler();
}

static __forceinline void event2_newevent_x(int no, evt t, uint data, evfunc2 func)
{
    if (((int)t) <= 0)
    {
        func(data);
        return;
    }

    event2_newevent_xx(no, t * CYCLE_UNIT, data, func);
}

static __forceinline void event2_newevent(int no, evt t, uint data)
{
    event2_newevent_x(no, t, data, eventtab2[no].handler);
}
static __forceinline void event2_newevent2(evt t, uint data, evfunc2 func)
{
    event2_newevent_x(-1, t, data, func);
}
static __forceinline void event2_remevent(int no)
{
    eventtab2[no].active = 0;
}